package cn.jboa.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import cn.jboa.dao.BaseDao;

@SuppressWarnings("unchecked")
public abstract class BaseHibernateDaoSupport<T> extends HibernateDaoSupport implements BaseDao<T> {
    private Class<T> cls;

    public BaseHibernateDaoSupport() {
        cls = (Class<T>) ((ParameterizedType) this.getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public void save(T instance) {
        this.getHibernateTemplate().save(instance);
    }

    public void update(T instance) {
        this.getHibernateTemplate().update(instance);
    }

    public void saveOrUpdate(T instance) {
        this.getHibernateTemplate().saveOrUpdate(instance);
    }

    public T merge(T instance) {
        return this.getHibernateTemplate().merge(instance);
    }

    public void delete(T instance) {
        this.getHibernateTemplate().delete(instance);
    }

    public void delete(Collection<T> instances) {
        this.getHibernateTemplate().deleteAll(instances);
    }

    public Integer delete(final Object[] ids) {
        return this.getHibernateTemplate().execute(new HibernateCallback<Integer>() {
            public Integer doInHibernate(Session arg0)
                    throws HibernateException, SQLException {
                String hql = "delete from " + cls.getSimpleName() + " where id in(:ids)"; // 1,2,3,...
                return arg0.createQuery(hql).setParameterList("ids", ids).executeUpdate();
            }
        });
    }

    public T get(Serializable id) {
        return this.getHibernateTemplate().get(cls, id);
    }

    public List<T> findAll() {
        return this.getHibernateTemplate().find("from " + cls.getSimpleName());// from Xxx
    }

    public <E> List<E> findForPage(final String hql, final int pageNo, final int pageSize,
                                   final Object... values) {
        return this.getHibernateTemplate().execute(new HibernateCallback<List<E>>() {

            public List<E> doInHibernate(Session arg0)
                    throws HibernateException, SQLException {
                Query query = arg0.createQuery(hql);
                if (values != null && values.length != 0) {
                    for (int i = 0; i < values.length; ++i) {
                        query.setParameter(i, values[i]);
                    }
                }
                // query.setProperties(bean);
                query.setFirstResult((pageNo - 1) * pageSize);
                query.setMaxResults(pageSize);
                return query.list();
            }
        });
    }

    // select count(*) + from Xxx where....
    // select ... from A, B where ...
    public Number getTotalCount(String hql, Object... values) {
        if (hql.startsWith("select "))
            hql = "select count(*) " + hql.substring(hql.indexOf(" from ") + 1);
        else
            hql = "select count(*) " + hql;
        return (Number) this.getHibernateTemplate().find(hql, values).get(0);
        // this.getHibernateTemplate().findByValueBean(queryString, valueBean)
    }

    public <E> List<E> find(String hql, Object... values) {
        return this.getHibernateTemplate().find(hql, values);
    }

}
